package version

import (
	"errors"
	"fmt"
	"strconv"
	"strings"
)

type Version struct {
	Ver                 string
	VerInt              uint32
	Major, Minor, Patch int8
}

// FromString 解析版本，必须符合 v1.23.4 或者 1.23.4结构
func FromString(ver string) (data Version, err error) {
	err = errors.New("version error")
	if len(ver) < 5 {
		return
	}
	if strings.ToLower(string(ver[0])) != "v" {
		ver = "v" + ver
	}
	v := strings.SplitN(ver[1:], ".", 3)
	if len(v) != 3 {
		return
	}

	n, _err := strconv.ParseInt(v[0], 10, 8)
	if _err != nil {
		return
	}
	data.Major = int8(n)
	n, _err = strconv.ParseInt(v[1], 10, 8)
	if _err != nil {
		return
	}
	data.Minor = int8(n)
	n, _err = strconv.ParseInt(v[2], 10, 8)
	if _err != nil {
		return
	}
	data.Patch = int8(n)
	data.VerInt = VerToUint32(data.Major, data.Minor, data.Patch)
	data.Ver = fmt.Sprintf("v%d.%d.%d", data.Major, data.Minor, data.Patch)
	err = nil
	return
}

func FromVer(major, minor, patch int8) Version {
	ver := Version{Major: major, Minor: minor, Patch: patch}
	ver.VerInt = VerToUint32(major, minor, patch)
	ver.Ver = fmt.Sprintf("v%d.%d.%d", major, minor, patch)
	return ver
}

func VerToUint32(major, minor, patch int8) (r uint32) {
	r = (uint32(major) & 0xff) << 16
	r |= (uint32(minor) & 0xff) << 8
	r |= uint32(patch) & 0xff
	return
}

func (ver Version) String() string {
	return ver.Ver
}

func (ver Version) MarshalJSON() ([]byte, error) {
	return []byte(`"` + ver.Ver + `"`), nil
}

func (ver *Version) UnmarshalJSON(b []byte) (err error) {
	if len(b) <= 2 {
		*ver = Version{}
		return nil
	}
	if b[0] == '"' && b[len(b)-1] == '"' {
		b = b[1 : len(b)-1]
	}
	*ver, err = FromString(string(b))
	return nil
}
